
#include <generated/uapi/linux/version.h>



#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/stddef.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#include <asm/unaligned.h>




#include "cl1026.h"

#define RESET_COLOR   "\033[0m"
#define RED_COLOR     "\033[31m"
#define GREEN_COLOR   "\033[32m"
#define YELLOW_COLOR  "\033[33m"
#define BLUE_COLOR    "\033[34m"
#define MAGENTA_COLOR "\033[35m"
#define CYAN_COLOR    "\033[36m"

// #define CL_DBG(fmt...)   printk(fmt)
// // do {
// // printk("CL1026 [%s]-%d:", __FUNCTION__, __LINE__);
// // printk(fmt);
// // }while(0)

#define CL_DBG(fmt,...)   \
	do {\
		printk("[CL1026][%4d][%-20s] " fmt "", \
            __LINE__, __FUNCTION__, ##__VA_ARGS__); \
	}while(0)
#define CL_ERR(fmt,...)   \
	do {\
		printk("[CL1026][%4d][%-20s] " RED_COLOR "ERROR:" RESET_COLOR " " fmt "", \
            __LINE__, __FUNCTION__, ##__VA_ARGS__); \
	}while(0)



#define CL1026_LRCK (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
#define CL1026_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)


#define  snd_soc_write_cl1026(codec,addr,value)  		snd_soc_component_write(codec, addr,  value);
#define  snd_soc_update_cl1026(component,reg,mask,val) 	snd_soc_component_update_bits(component,reg,mask,val)
#define  snd_soc_read_cl1026(codec,addr)  snd_soc_component_read32(codec, addr);



struct sp_config {
	u8 spc, mmcc, spfs;
	u32 lrckfreq;
};

struct  cl1026_priv{
	struct gpio_desc *gpiod_spk_ctl;
	struct sp_config config;
	struct regmap *regmap;
	struct clk *mclk;
	unsigned int sysclk;
	struct snd_pcm_hw_constraint_list *sysclk_constraints;
	int shutdwn_delay;
	bool hp_mute;
	bool hp_inserted;
	long force_muted;    //--强制静音


    long  playback_path;
    long  capture_path;

};

struct snd_pcm_constr_list {
	int count;
	u32 *list;
};


struct cl1026_mclk_div {
	u32 mclk, lrckfreq;
	u8 mmcc;
};

static struct cl1026_mclk_div cl1026_mclk_coeffs[] = {
	/* MCLK, LRCK, MMCC[5:0] */
	{5644800, 11025, 0x30},
	{5644800, 22050, 0x20},
	{5644800, 44100, 0x10},

	{6144000,  8000, 0x38},
	{6144000, 12000, 0x30},
	{6144000, 16000, 0x28},
	{6144000, 24000, 0x20},
	{6144000, 32000, 0x18},
	{6144000, 48000, 0x10},

};


struct cl1026_priv *globe_cl1026;
static struct snd_soc_component *cl1026_codec;

struct workqueue_struct *spk_monitor_wq;
struct delayed_work spk_delay_work;


static unsigned int rates_12288[] = {
	8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000,
};

static struct snd_pcm_hw_constraint_list constraints_12288 = {
	.count	= ARRAY_SIZE(rates_12288),
	.list	= rates_12288,
};

static unsigned int rates_112896[] = {
	8000, 11025, 22050, 44100,
};

static struct snd_pcm_hw_constraint_list constraints_112896 = {
	.count	= ARRAY_SIZE(rates_112896),
	.list	= rates_112896,
};

static unsigned int rates_12[] = {
	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
	48000, 88235, 96000,
};

static struct snd_pcm_hw_constraint_list constraints_12 = {
	.count	= ARRAY_SIZE(rates_12),
	.list	= rates_12,
};

// void cl1026_enable_spk(struct cl1026_priv *cl1026, bool enable)
// {
// 	if (!cl1026 || !cl1026->gpiod_spk_ctl)
// 		return;
// 	CL_DBG("enable = %d\n", enable);
// 	gpiod_set_value(cl1026->gpiod_spk_ctl, enable);
// }

// static void spk_delay_work_handle(struct work_struct *work)
// {
// 	CL_DBG("globe_cl1026->hp_inserted = %d\n", globe_cl1026->hp_inserted);
// 	if (!globe_cl1026->hp_inserted)
// 		cl1026_enable_spk(globe_cl1026, true);
// }


static bool cl1026_volatile_reg(struct device *dev, unsigned int reg)
{
	if (reg <= 255)	
		return true;
	else
		return false;
}

static bool cl1026_readable_reg(struct device *dev, unsigned int reg)
{
	if (reg <= 255)	
		return true;
	else
		return false;
}
static const struct reg_default cl1026_reg_defaults[] = {
	{ 1, 0xF1 },{ 2, 0xDF },{ 3, 0x3F },{ 4, 0x60 },
	{ 5, 0x77 },{ 6, 0x04 },{ 7, 0x00 },{ 8, 0x15 },
	{ 9, 0x06 },{ 10, 0x00 },{ 11, 0x00 },{ 12, 0x00 },
	{ 13, 0x00 },{ 14, 0x00 },{ 15, 0x00 },{ 16, 0x00 },
	{ 17, 0x00 },{ 18, 0x02 },{ 19, 0x02 },{ 20, 0x00 },
	{ 21, 0x00 },{ 22, 0x00 },{ 23, 0x7F },{ 24, 0x03 },
	{ 25, 0x00 },{ 26, 0x3F },{ 27, 0xE1 },{ 28, 0x00 },
	{ 29, 0x00 },{ 30, 0x08 },{ 31, 0x3F },{ 32, 0x3F },
	{ 33, 0x00 },{ 34, 0x00 },{ 35, 0x00 },{ 36, 0x00 },
	{ 37, 0x3F },{ 38, 0x3F },{ 94, 0x00 },
};

static struct regmap_config cl1026_regmap = {
	.reg_bits = 8,
	.val_bits = 8,
	// .reg_bits = 32,
	// .val_bits = 32,

	.max_register = CL1026_MAX_REGISTER,
	.reg_defaults = cl1026_reg_defaults,
	.num_reg_defaults = ARRAY_SIZE(cl1026_reg_defaults),
	.volatile_reg = cl1026_volatile_reg,
	.readable_reg = cl1026_readable_reg,
	.cache_type = REGCACHE_RBTREE,
};




static int cl1026_set_bias_level(struct snd_soc_component *codec,enum snd_soc_bias_level level)
{
	CL_DBG("set cl1026 bias level level = %d \n",level);
	if (level == SND_SOC_BIAS_ON) {
		snd_soc_component_update_bits(codec, CL1026_DMMCC, CL1026_MCLKDIS, 0);
		snd_soc_component_update_bits(codec, CL1026_PWRCTRL1, CL1026_PDN, 0);
	}else {
		//snd_soc_update_bits(codec, CL1026_PWRCTRL1, CL1026_PDN, 1);
		//snd_soc_update_bits(codec, CL1026_DMMCC, CL1026_MCLKDIS, 1);
	}
	//codec->dapm.bias_level = level;

	return 0;
}


static DECLARE_TLV_DB_SCALE(micpga_tlv, 0, 100, 0);
static DECLARE_TLV_DB_SCALE(ipdig_tlv, -9600, 100, 0);
static DECLARE_TLV_DB_SCALE(adc_20db_tlv, 0, 2000, 0);

static const char * const cl1026_pgaa[] = { "Line 1", "Mic 1" };
static const char * const cl1026_pgab[] = { "Line 2", "Mic 2" };

static const struct soc_enum pgaa_enum =
	SOC_ENUM_SINGLE(CL1026_ADCIPC, 3, ARRAY_SIZE(cl1026_pgaa), cl1026_pgaa);
static const struct soc_enum pgab_enum =
	SOC_ENUM_SINGLE(CL1026_ADCIPC, 7, ARRAY_SIZE(cl1026_pgab), cl1026_pgab);

static const char * const cl1026_ip_swap[] = {"Stereo", "Mono 1", "Mono 2", "Swap 1/2"};
static const struct soc_enum ip_swap_enum =
	SOC_ENUM_SINGLE(CL1026_MIOPC, 6, ARRAY_SIZE(cl1026_ip_swap), cl1026_ip_swap);

static const char * const cl1026_ng_delay[] = {"50ms", "100ms", "150ms", "200ms"};
static const struct soc_enum ng_delay_enum =
	SOC_ENUM_SINGLE(CL1026_NGCAB, 0, ARRAY_SIZE(cl1026_ng_delay), cl1026_ng_delay);



static const struct snd_kcontrol_new pgaa_mux =
	SOC_DAPM_ENUM("Left Analog Input Capture Mux", pgaa_enum);
static const struct snd_kcontrol_new pgab_mux =
	SOC_DAPM_ENUM("Right Analog Input Capture Mux", pgab_enum);
static const struct snd_kcontrol_new input_left_mixer[] = {
	SOC_DAPM_SINGLE("ADC Left Input", CL1026_PWRCTRL1, 5, 1, 1),
	SOC_DAPM_SINGLE("DMIC Left Input", CL1026_PWRCTRL1, 4, 1, 1),};
static const struct snd_kcontrol_new input_right_mixer[] = {
	SOC_DAPM_SINGLE("ADC Right Input", CL1026_PWRCTRL1, 7, 1, 1),
	SOC_DAPM_SINGLE("DMIC Right Input", CL1026_PWRCTRL1, 6, 1, 1),};




// static const unsigned int hpd_tlv[] = {TLV_DB_RANGE_HEAD(2),
// 	-102, 0, TLV_DB_SCALE_ITEM(-10200, 50, 0),
// 	1, 12, TLV_DB_SCALE_ITEM(0, 50, 0), 
// };  
static DECLARE_TLV_DB_SCALE(hpd_tlv, -10200, 50, 0);
static DECLARE_TLV_DB_SCALE(hpa_tlv, -5400, 200, 0);


//--这边逻辑取反
static const unsigned int limiter_tlv[] = {TLV_DB_RANGE_HEAD(2),
	0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),   // --假设给的值是0  那么逻辑取反的话就是 0B111 对应的值是 -30dB
											  //          值是1  那么逻辑取反的话就是 0B110 对应的值是 -24dB
											  //          值是2  那么逻辑取反的话就是 0B101 对应的值是 -18dB
	3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0),};

static const char * const cl1026_playback_path_mode[] = {
	"OPEN SPK","CLOSE SPK", "OPEN HP A","CLOSE HP A","OPEN HP B","CLOSE HP B","OPEN HP","CLOSE HP"
}; 
static const char * const cl1026_capture_path_mode[] = {
	"OPEN DIGITAL MIC", "CLOSE DIGITAL MIC", "OPEN MIC A", "CLOSE MIC A" , "OPEN MIC B" ,"CLOSE MIC B"
};
static const char * const cl1026_mute_mode[] = {
	"MUTE OFF", "MUTE ON",
};

static SOC_ENUM_SINGLE_DECL(cl1026_playback_path_type,
	0, 0, cl1026_playback_path_mode);

static SOC_ENUM_SINGLE_DECL(cl1026_capture_path_type,
	0, 0, cl1026_capture_path_mode);

static SOC_ENUM_SINGLE_DECL(cl1026_mute_type,
	0, 0, cl1026_mute_mode);



static int cl1026_playback_path_get(struct snd_kcontrol *kcontrol,
				   struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
	struct cl1026_priv* cl1026 = snd_soc_component_get_drvdata(component);

	// CL_DBG("CL1026 %s : playback_path %ld\n", __func__, cl1026->playback_path);

	ucontrol->value.integer.value[0] = cl1026->playback_path;

	return 0;
}

static int cl1026_playback_path_config(struct snd_soc_component *component,
				      long int pre_path, long int target_path)
{

    int reg = 0;
	struct cl1026_priv *cl1026 = snd_soc_component_get_drvdata(component);

	cl1026->playback_path = target_path;

    // mutex_lock(&cl1026->clk_lock);
	// if (cl1026->playback_path != OFF) {
	// 	if (cl1026->clk_playback == 0) {
	// 		clk_prepare_enable(cl1026->mclk);
	// 		cl1026->clk_playback++;
	// 	}
	// } else {
	// 	if (cl1026->clk_playback > 0) {
	// 		clk_disable_unprepare(cl1026->mclk);
	// 		cl1026->clk_playback--;
	// 	}
	// }
	// mutex_unlock(&cl1026->clk_lock);
    switch (cl1026->playback_path) {
        case  OPEN_SPK_E:
            
        break;
        case CLOSE_SPK:
        break;

        case OPEN_HP_A:
            snd_soc_update_cl1026(component,CL1026_MICBSVDDA,CL1026_MICBSVDDA_HPA,1<<5); //设置HPA 打开
            snd_soc_update_cl1026(component,CL1026_PWRCTRL3,CL1026_PDN_HP,0);
        break;
        case CLOSE_HP_A:
            snd_soc_update_cl1026(component,CL1026_MICBSVDDA,CL1026_MICBSVDDA_HPA,0<<5); //设置HPA 关闭
            reg = snd_soc_read_cl1026(component,CL1026_MICBSVDDA);
            CL_DBG("%s : CL1026_MICBSVDDA = %x\n",__func__,reg);
            if((reg&CL1026_MICBSVDDA_HPB) ==0 )            
                snd_soc_update_cl1026(component,CL1026_PWRCTRL3,CL1026_PDN_HP,1);
        break;

        case OPEN_HP_B:
            snd_soc_update_cl1026(component,CL1026_MICBSVDDA,CL1026_MICBSVDDA_HPB,1<<6); //设置HPB 打开
            snd_soc_update_cl1026(component,CL1026_PWRCTRL3,CL1026_PDN_HP,0);
        break;
        case CLOSE_HP_B:
            snd_soc_update_cl1026(component,CL1026_MICBSVDDA,CL1026_MICBSVDDA_HPB,0<<6); //设置HPB 关闭
            reg = snd_soc_read_cl1026(component,CL1026_MICBSVDDA);
            CL_DBG("%s : CL1026_MICBSVDDA = %x\n",__func__,reg);
            if((reg&CL1026_MICBSVDDA_HPA) ==0 )    
                snd_soc_update_cl1026(component,CL1026_PWRCTRL3,CL1026_PDN_HP,1);
        break;
        case OPEN_HP:
            snd_soc_update_cl1026(component,CL1026_MICBSVDDA,CL1026_MICBSVDDA_HPA,1<<5); //设置HPA 打开
            snd_soc_update_cl1026(component,CL1026_MICBSVDDA,CL1026_MICBSVDDA_HPB,1<<6);
        break;
        case CLOSE_HP:
            snd_soc_update_cl1026(component,CL1026_MICBSVDDA,CL1026_MICBSVDDA_HPB,0<<6); //设置HPB 打开
            snd_soc_update_cl1026(component,CL1026_MICBSVDDA,CL1026_MICBSVDDA_HPB,0<<5); //设置HPA 关闭
            snd_soc_update_cl1026(component,CL1026_PWRCTRL3,CL1026_PDN_HP,1);
        break;
    }
    return 0;


}
static int cl1026_playback_path_put(struct snd_kcontrol *kcontrol,
				   struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
	struct cl1026_priv *cl1026 = snd_soc_component_get_drvdata(component);
    static int isSet = 0;
	if (cl1026->playback_path == ucontrol->value.integer.value[0] && isSet == 1) {
		CL_DBG("playback_path is not changed!\n"); 
		return 0;
	}
    isSet = 1;
	return cl1026_playback_path_config(component, cl1026->playback_path,
					  ucontrol->value.integer.value[0]);
}


static int cl1026_capture_path_get(struct snd_kcontrol *kcontrol,
				  struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
	struct cl1026_priv* cl1026  = snd_soc_component_get_drvdata(component);

	// CL_DBG("CL1026 %s : capture_path %ld\n", __func__,cl1026->capture_path);

	ucontrol->value.integer.value[0] = cl1026->capture_path;
	return 0;
}


static int cl1026_capture_path_config(struct snd_soc_component *component,
				     long pre_path, long target_path)
{
	struct cl1026_priv *cl1026 = snd_soc_component_get_drvdata(component);

	cl1026->capture_path = target_path;

    switch (cl1026->capture_path)
    {
    case OPEN_DIGITAL_MIC:
		snd_soc_update_cl1026(component,CL1026_PWRCTRL1,CL1026_PDN_DMICB,0<<6);
		snd_soc_update_cl1026(component,CL1026_PWRCTRL1,CL1026_PDN_DMICB,0<<4);
		snd_soc_update_cl1026(component,CL1026_PWRCTRL1,CL1026_PDN_ADCB,1<<7);
		snd_soc_update_cl1026(component,CL1026_PWRCTRL1,CL1026_PDN_ADCA,1<<5);
    	break;
    case CLOSE_DIGITAL_MIC:
		snd_soc_update_cl1026(component,CL1026_PWRCTRL1,CL1026_PDN_DMICB,0<<6);
		snd_soc_update_cl1026(component,CL1026_PWRCTRL1,CL1026_PDN_DMICB,0<<4);
		snd_soc_update_cl1026(component,CL1026_PWRCTRL1,CL1026_PDN_ADCB,0<<7);
		snd_soc_update_cl1026(component,CL1026_PWRCTRL1,CL1026_PDN_ADCA,0<<5);
		break;

    case SELECT_MIC_A:
    	snd_soc_update_cl1026(component,CL1026_ADCIPC,CL1026_ADCIPC_MICB_LINEB,1<<7);

    break;    
    case SELECT_LINE_A:
    	snd_soc_update_cl1026(component,CL1026_ADCIPC,CL1026_ADCIPC_MICB_LINEB,0<<7);
    	break;


    case SELECT_MIC_B:
    	snd_soc_update_cl1026(component,CL1026_ADCIPC,CL1026_ADCIPC_MICA_LINEA,1<<3);
    break;
    case SELECT_LINE_B:
		snd_soc_update_cl1026(component,CL1026_ADCIPC,CL1026_ADCIPC_MICA_LINEA,0<<3);
    	break;
    
    default:
        break;
    }
	return 0;
}


static int cl1026_capture_path_put(struct snd_kcontrol *kcontrol,
				  struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
	struct cl1026_priv* cl1026  = snd_soc_component_get_drvdata(component);
    static int isSet = 0;
	if (cl1026->capture_path == ucontrol->value.integer.value[0] && isSet == 1) {
		CL_DBG("%s : capture_path is not changed!\n",
		    __func__);
		return 0;
	}
    isSet = 1;
	return cl1026_capture_path_config(component, cl1026->capture_path,
					 ucontrol->value.integer.value[0]);
}

static int cl1026_mute_path_get(struct snd_kcontrol *kcontrol,
				  struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
	struct cl1026_priv* cl1026  = snd_soc_component_get_drvdata(component);

	CL_DBG("CL1026 %s : force_muted %ld\n", __func__,cl1026->force_muted);

	ucontrol->value.integer.value[0] = cl1026->force_muted;
	return 0;
}

static int cl1026_muted_path_put(struct snd_kcontrol *kcontrol,
				  struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
	struct cl1026_priv* cl1026  = snd_soc_component_get_drvdata(component);
    
	
	if(!ucontrol->value.integer.value[0]){
		cl1026->force_muted = 0;
		snd_soc_update_cl1026(component,CL1026_HPDC,1<<1,0<<1);
		snd_soc_update_cl1026(component,CL1026_HPDC,1<<0,0<<0);
	}else {
		cl1026->force_muted = 1;
		snd_soc_update_cl1026(component,CL1026_HPDC,1<<1,1<<1);
		snd_soc_update_cl1026(component,CL1026_HPDC,1<<0,1<<0);
	}

	return 0;
}


//--这边逻辑取反
static const DECLARE_TLV_DB_SCALE(attn_tlv, -6300, 100, 1);


static const struct snd_kcontrol_new cl1026_snd_controls[] = {
	// SOC_DOUBLE_R_SX_TLV("HP Analog Playback Volume",
	// 		CL1026_HPAAVOL, CL1026_HPBAVOL, 0,
	// 		0x4c, 0x06, hpa_tlv),
	//  SOC_DOUBLE_R_SX_TLV("HP Digital Playback Volume",
	//  		CL1026_HPADVOL, CL1026_HPBDVOL,0x00,
	// 		 0x00,0x34,hpd_tlv),

	SOC_DOUBLE_R_S_TLV("HP_A_PlaybackVolume",    //HP Analog Playback Volume
	 		CL1026_HPAAVOL, CL1026_HPBAVOL,1,
			-27,3,5,0,hpa_tlv),			//范围从0~30    0:27	
	

	SOC_DOUBLE_R_S_TLV("HP_D_PlaybackVolume",    //HP Digital Playback Volume
	 		CL1026_HPADVOL, CL1026_HPBDVOL,0x00,
			-204,24,7,0,hpd_tlv),		//  范围从0~228	0:204			真正读出来的值需要做 v= v & 0x010000;不然读出来的数值有误的


	SOC_DOUBLE_R("HP Analog Playback Mute", CL1026_HPAAVOL,
			CL1026_HPBAVOL, 7, 1, 1),

	// SOC_DOUBLE_R_SX_TLV("Input PGA Analog Volume", 
	//		CL1026_MICPGAAVOL,CL1026_MICPGABVOL, 5,
	// 		0x00,0x30, micpga_tlv),
	SOC_DOUBLE_R_TLV("Input PGA Analog Volume", 
			CL1026_MICPGAAVOL, CL1026_MICPGABVOL, 0, 
			0x18, 0, micpga_tlv),      //范围从0~24 0:0

	// SOC_DOUBLE_R_SX_TLV("Input Path Digital Volume", 
	// 		CL1026_IPADVOL,CL1026_IPBDVOL, 0, 
	// 		0xA0, 0x0C, ipdig_tlv),		

	SOC_DOUBLE_R_S_TLV("Input Path Digital Volume",
	 		CL1026_IPADVOL, CL1026_IPBDVOL,0x00,
			-96,12,7,0,ipdig_tlv),		//范围从0~108	0:96


	SOC_DOUBLE_R("MIC Preamp Switch", CL1026_MICPGAAVOL,
			CL1026_MICPGABVOL, 6, 1, 1),

	SOC_SINGLE_TLV("ADC A 20db",
			CL1026_ADCIPC, 2, 
			0x01, 1, adc_20db_tlv),

	SOC_SINGLE_TLV("ADC B 20db",
		       CL1026_ADCIPC, 6, 
			0x01, 1, adc_20db_tlv),

	SOC_DOUBLE("Input Path Digital Mute", CL1026_ADCIPC, 0, 4, 1, 1),
	SOC_DOUBLE("HP Digital Playback left Mute", CL1026_HPDC, 0, 1, 1, 1),
	SOC_SINGLE("PGA Soft Ramp Switch", CL1026_MIOPC, 3, 1, 0),
	SOC_SINGLE("Analog 0 Cross Switch", CL1026_MIOPC, 2, 1, 0),
	SOC_SINGLE("Digital Soft Ramp Switch", CL1026_MIOPC, 1, 1, 0),
	SOC_SINGLE("Analog Output Soft Ramp Switch", CL1026_MIOPC, 0, 1, 0),

	SOC_DOUBLE("ADC Signal Polarity Switch", CL1026_ADCIPC, 1, 5, 1, 0),

	SOC_SINGLE("HP Limiter Attack Rate", CL1026_LIMATTRATEHP, 0, 0x3F, 0),
	SOC_SINGLE("HP Limiter Release Rate", CL1026_LIMRLSRATEHP, 0, 0x3F, 0),
	SOC_SINGLE("HP Limiter Switch", CL1026_LIMRLSRATEHP, 7, 1, 0),
	SOC_SINGLE("HP Limiter All Channels Switch", CL1026_LIMRLSRATEHP, 6, 1, 0),


	
	SOC_SINGLE_TLV("HP Limiter Max Threshold Vol", CL1026_LMAXMINHP, 5, 7, 1, limiter_tlv),
	SOC_SINGLE_TLV("HP Limiter Min Threshold Vol", CL1026_LMAXMINHP, 2, 7, 1, limiter_tlv),


	SOC_SINGLE("ALC Attack Rate Volume", CL1026_ALCARATE, 0, 0x3F, 0),
	SOC_SINGLE("ALC Release Rate Volume", CL1026_ALCRRATE, 0, 0x3F, 0),
	SOC_DOUBLE("ALC Switch", CL1026_ALCARATE, 6, 7, 1, 0),

	
	SOC_SINGLE_TLV("ALC Max Threshold Volume", CL1026_ALCMINMAX, 5, 7, 0, limiter_tlv),
	SOC_SINGLE_TLV("ALC Min Threshold Volume", CL1026_ALCMINMAX, 2, 7, 0, limiter_tlv),



	SOC_DOUBLE("NG Enable Switch", CL1026_NGCAB, 6, 7, 1, 0),
	SOC_SINGLE("NG Boost Switch", CL1026_NGCAB, 5, 1, 0),
	SOC_SINGLE("NG Threshold", CL1026_NGCAB, 2, 7, 0),
    SOC_SINGLE("HP Amp CTRL", CL1026_PWRCTRL3, 0, 1,0),



	SOC_ENUM("NG Delay", ng_delay_enum),

	SOC_DOUBLE_R_TLV("IP2ASP Volume", CL1026_IPA2ASPA, CL1026_IPB2ASPB, 0, 0x3F, 1, attn_tlv),
	SOC_DOUBLE_R_TLV("ASP2ASP Volume", CL1026_ASPA2ASPA, CL1026_ASPB2ASPB, 0, 0x3F, 1, attn_tlv),
	SOC_DOUBLE_R_TLV("IP2HP Volume", CL1026_IPA2HPA, CL1026_IPB2HPB, 0, 0x3F, 1, attn_tlv),
	SOC_DOUBLE_R_TLV("ASP2HP Volume", CL1026_ASPA2HPA, CL1026_ASPB2HPB, 0, 0x3F, 1, attn_tlv),


	SOC_ENUM("IP Digital Swap/Mono Select", ip_swap_enum),

    SOC_ENUM_EXT("Playback Opt", cl1026_playback_path_type,
		     cl1026_playback_path_get, cl1026_playback_path_put),

	SOC_ENUM_EXT("Capture MIC Opt", cl1026_capture_path_type,
		     cl1026_capture_path_get, cl1026_capture_path_put),

	SOC_ENUM_EXT("Mute", cl1026_mute_type,
		     cl1026_mute_path_get, cl1026_muted_path_put),
};






static int cl1026_init_regs(struct snd_soc_component *codec)
{
	CL_DBG(" init all regs...\n");

#if 0
    snd_soc_write_cl1026(codec, 0x00,  0x68);
    snd_soc_write_cl1026(codec, CL1026_PWRCTRL1,  0x00);
    // snd_soc_write_cl1026(codec, CL1026_PWRCTRL1,  0x08);//打开LDO电源
    snd_soc_update_cl1026(codec,CL1026_PWRCTRL1,CL1026_PDN_LDO,1<<3);
    snd_soc_update_cl1026(codec,CL1026_PWRCTRL1,CL1026_PDN,0);

    snd_soc_update_cl1026(codec,CL1026_DMMCC,CL1026_FREQ_DIV,2<<1); //设置主频分频比值
    snd_soc_update_cl1026(codec,CL1026_DMMCC,CL1026_MCLKDIS,0);


    snd_soc_update_cl1026(codec,CL1026_PWRCTRL2,CL1026_PDN_ASP_SDO,0);  //打开I2S 输入输出
    snd_soc_update_cl1026(codec,CL1026_PWRCTRL2,CL1026_PDN_ASP_SDI,0);  //打开I2S 输入输出

	
#endif
#if 1
	snd_soc_write_cl1026(codec, 0x00,  0x68);
	snd_soc_write_cl1026(codec, 0x0A,  0x88);
	snd_soc_write_cl1026(codec, 0x01,  0x00);
	snd_soc_write_cl1026(codec, 0x01,  0x08);
	snd_soc_write_cl1026(codec, 0x05,  0x65);
	snd_soc_write_cl1026(codec, 0x02,  0x1F);
	snd_soc_write_cl1026(codec, 0x06,  0x04);
	snd_soc_write_cl1026(codec, 0x02,  0x13);
	// snd_soc_write_cl1026(codec, 0x39,  0x14);
	snd_soc_write_cl1026(codec, 0x12,  0x02);
	snd_soc_write_cl1026(codec, 0x13,  0x02);

	snd_soc_write_cl1026(codec, 0x21,  0x00);
	snd_soc_write_cl1026(codec, 0x22,  0x00);
	snd_soc_write_cl1026(codec, 0x23,  0x00);
	snd_soc_write_cl1026(codec, 0x24,  0x00);
	snd_soc_write_cl1026(codec, 0x03,  0x1c);
#endif
	//////////////////////////
	//snd_soc_write_cl1026(codec, 0x1F,  0x00);
	//snd_soc_write_cl1026(codec, 0x20,  0x00);
	snd_soc_write_cl1026(codec, 0x2c,  0xc1);
	// snd_soc_write_cl1026(codec, 0x20,  0x3F);
	// 关闭mic输出到headset
	// ////////////////////////////////
	// snd_soc_write_cl1026(codec, 0x21,  0x00);
	// snd_soc_write_cl1026(codec, 0x22,  0x00);
	// snd_soc_write_cl1026(codec, 0x23,  0x00);
	// snd_soc_write_cl1026(codec, 0x24,  0x00);
	return 0;
}

static int cl1026_probe(struct snd_soc_component *codec)
{
	int ret = 0;

	struct cl1026_priv*cl1026 = snd_soc_component_get_drvdata(codec);

	cl1026_codec = codec;

	CL_DBG(" alsa start ....\n");

	snd_soc_component_init_regmap(codec, cl1026->regmap);
//	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
//	if (ret < 0) {
//		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
//		return ret;
//	}
	cl1026_set_bias_level(codec, SND_SOC_BIAS_ON);

	/* initialize codec */
	//CL_DBG(" CL1026_PWRCTRL1 0x%x \n",snd_soc_read(codec, CL1026_PWRCTRL1));
	//CL_DBG(" CL1026_PWRCTRL2 0x%x \n",snd_soc_read(codec, CL1026_PWRCTRL2));
	
	cl1026_init_regs(codec);
	//CL_DBG(" CL1026_PWRCTRL3 0x%x \n",snd_soc_read(codec, 0x06));
	/* select EXT CLK as mclk */
	//cl1026->mclksel = CL1026_CLKID;
	cl1026->mclk = devm_clk_get(codec->dev, "mclk");
	if (IS_ERR(cl1026->mclk)){
		CL_ERR("Failed to get mclk\n");
		return PTR_ERR(cl1026->mclk);;
	}
	
	ret = clk_prepare_enable(cl1026->mclk);
	if (ret){
		CL_ERR("Failed to enable mclk\n");
		return ret;
	}
    //shiguangyuan delete clk
	CL_DBG("alsa get the mclk=%ld\n",clk_get_rate(cl1026->mclk));
    CL_DBG("alsa driver finish.... \n");
	return ret;
}

static void cl1026_remove(struct snd_soc_component *codec)
{
	cl1026_set_bias_level(codec, SND_SOC_BIAS_OFF);
}


static int cl1026_suspend(struct snd_soc_component *codec)
{
	CL_DBG(" suspend ...\n");
	cl1026_set_bias_level(codec, SND_SOC_BIAS_OFF);

	return 0;
}

static int cl1026_resume(struct snd_soc_component *codec)
{
	CL_DBG(" resume ...\n");
	cl1026_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
	return 0;
}


static const struct snd_soc_dapm_widget dit_widgets[] = {
	SND_SOC_DAPM_OUTPUT("HPOUTA"),
	SND_SOC_DAPM_OUTPUT("HPOUTB"),

	SND_SOC_DAPM_INPUT("LINEIN1"),
	SND_SOC_DAPM_INPUT("LINEIN2"),
	SND_SOC_DAPM_INPUT("MIC1"),
	SND_SOC_DAPM_INPUT("MIC2"),

	SND_SOC_DAPM_DAC("HP Amp", NULL, CL1026_PWRCTRL3, 0, 0),

	SND_SOC_DAPM_MIXER_NAMED_CTL("Input Left Capture", SND_SOC_NOPM,
			 0, 0, input_left_mixer, ARRAY_SIZE(input_left_mixer)),
	SND_SOC_DAPM_MIXER_NAMED_CTL("Input Right Capture", SND_SOC_NOPM,
			0, 0, input_right_mixer, ARRAY_SIZE(input_right_mixer)),

	SND_SOC_DAPM_ADC("DMIC Left", NULL, CL1026_PWRCTRL1, 6, 0),
	SND_SOC_DAPM_ADC("DMIC Right", NULL, CL1026_PWRCTRL1, 4, 0),
	
};

//--
static const struct snd_soc_dapm_route dit_routes[] = {
	{"HPOUTA", NULL, "ASP Playback"},
	{"HPOUTA", NULL, "ASP Playback"},
};



static struct snd_soc_component_driver soc_codec_dev_cl1026 = {

	.probe = cl1026_probe,
	.remove = cl1026_remove,
	.suspend = cl1026_suspend,
	.resume = cl1026_resume,
	.set_bias_level = cl1026_set_bias_level,
	// .dapm_widgets = cl1026_dapm_widgets,
	// .num_dapm_widgets = ARRAY_SIZE(cl1026_dapm_widgets),
	// .dapm_routes = cl1026_audio_map,
	// .num_dapm_routes = ARRAY_SIZE(cl1026_audio_map),

	.dapm_widgets		= dit_widgets,
	.num_dapm_widgets	= ARRAY_SIZE(dit_widgets),
	.dapm_routes		= dit_routes,
	.num_dapm_routes	= ARRAY_SIZE(dit_routes),


	.controls = cl1026_snd_controls,
	.num_controls = ARRAY_SIZE(cl1026_snd_controls),


};


static int cl1026_pcm_startup(struct snd_pcm_substream *substream,
			       struct snd_soc_dai *dai)
{
	bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
	if (playback) {
		msleep(50);
	} else {
		
	}
	return 0;
}


static int cl1026_pcm_hw_params(struct snd_pcm_substream *substream,
				 struct snd_pcm_hw_params *params,
				 struct snd_soc_dai *dai)
{

	struct snd_soc_component *codec = dai->component;	
	struct cl1026_priv *priv = snd_soc_component_get_drvdata(codec);

	int lrckfreq = params_rate(params);
	int i, index = -1;
	if (priv->config.mmcc & CL1026_MS_MASTER) {

		for (i = 0; i < ARRAY_SIZE(cl1026_mclk_coeffs); i++) {
			if (//cl1026_mclk_coeffs[i].mclk == priv->mclk &&
				cl1026_mclk_coeffs[i].lrckfreq == lrckfreq)
				index = i;
		}

		if (index < 0){
			CL_DBG("cl1026_pcm_hw_params, mclk = %d\n", index);
			return -EINVAL;
		} 

		dev_dbg(codec->dev,
			 "DAI[ ]: lrckfreq %u, MMCC[5:0] = %x\n",
			  lrckfreq,cl1026_mclk_coeffs[index].mmcc);
			 

		priv->config.mmcc &= 0xC0;
		priv->config.mmcc |= cl1026_mclk_coeffs[index].mmcc;
		priv->config.spc &= 0xFC;
		/* Use SCLK=64*Fs */
		//if (priv->mclk >= 6400000)
		//	priv->config.spc |= CL1026_MCK_SCLK_64FS;
		//else
		//	priv->config.spc |= CL1026_MCK_SCLK_MCLK;
	} else {
		priv->config.spc &= 0xFC;
		priv->config.spc |= CL1026_MCK_SCLK_64FS;
	}

	priv->config.lrckfreq = lrckfreq;

	//snd_soc_write(codec, CL1026_ASPC, priv->config.spc);
	snd_soc_write_cl1026(codec, CL1026_ASPMMCC, priv->config.mmcc);

	return 0;
}
static int cl1026_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
	
	struct snd_soc_component *codec = codec_dai->component;	
	struct cl1026_priv *priv = snd_soc_component_get_drvdata(codec);

	u8 spc, mmcc;

	spc = snd_soc_read_cl1026(codec, CL1026_ASPC);
	mmcc = snd_soc_read_cl1026(codec, CL1026_ASPMMCC);

	if (fmt == SND_SOC_DAIFMT_CBM_CFM) {
		mmcc |= CL1026_MS_MASTER;
	} else {
		mmcc &= ~CL1026_MS_MASTER;
	}

	if (fmt == SND_SOC_DAIFMT_I2S) {
		spc &= ~CL1026_SPDIF_PCM;
	} else {
		spc |= CL1026_SPDIF_PCM;
	}

//	inv = (fmt & SND_SOC_DAIFMT_INV_MASK);
	if (spc & CL1026_SPDIF_PCM) {
		spc &= ~CL1026_PCM_BIT_ORDER;
//		switch (format) {
//		case SND_SOC_DAIFMT_DSP_B:
//			if (inv == SND_SOC_DAIFMT_IB_IF)
//				spc |= cl1026_PCM_MODE0;
//			if (inv == SND_SOC_DAIFMT_IB_NF)
//				spc |= cl1026_PCM_MODE1;
//		break;
//		case SND_SOC_DAIFMT_DSP_A:
//			if (inv == SND_SOC_DAIFMT_IB_IF)
//				spc |= cl1026_PCM_MODE1;
//			break;
//		default:
//			return -EINVAL;
//		}
	}

	priv->config.spc = spc;
	priv->config.mmcc = mmcc;

	return 0;
}

static int cl1026_set_dai_sysclk(struct snd_soc_dai *codec_dai,
			      int clk_id, unsigned int freq, int dir)
{

	struct snd_soc_component *codec = codec_dai->component;	
	struct cl1026_priv *cl1026 = snd_soc_component_get_drvdata(codec);

    CL_DBG(" cl1026_set_dai_sysclk, freq = %d\n", freq);

	switch (freq) {
	case 11289600:
	case 18432000:
	case 22579200:
	case 36864000:
		cl1026->sysclk_constraints = &constraints_112896;
		cl1026->sysclk = freq;
		return 0;
	case 12288000:
	case 19200000:
	case 16934400:
	case 24576000:
	case 33868800:
		cl1026->sysclk_constraints = &constraints_12288;
		cl1026->sysclk = freq;
		return 0;
	case 12000000:
		cl1026->sysclk_constraints = &constraints_12;
		cl1026->sysclk = freq;
		return 0;
	}
	return -EINVAL;
	
}
static int cl1026_mute(struct snd_soc_dai *dai, int mute,int stream)
{
	struct snd_soc_component *codec = dai->component;	
	struct cl1026_priv *cl1026 = snd_soc_component_get_drvdata(codec);

	CL_DBG(" cl1026_mute, mute = %d\n", mute);
	//cl1026->muted = mute;
	if(cl1026->force_muted)
		return 0;
	if(mute){
		// cancel_delayed_work(&spk_delay_work);
		//off
		// cl1026_enable_spk(cl1026, false);
		// msleep(100);
		
		snd_soc_update_cl1026(codec,CL1026_HPDC,1<<1,1<<1);
		snd_soc_update_cl1026(codec,CL1026_HPDC,1<<0,1<<0);

	}else  {//if (dai->playback_active)

		snd_soc_update_cl1026(codec,CL1026_HPDC,1<<1,0<<1);
		snd_soc_update_cl1026(codec,CL1026_HPDC,1<<0,0<<0);

		//on
		// queue_delayed_work(spk_monitor_wq, &spk_delay_work,msecs_to_jiffies(150));
	}
	return 0;
}
#if 0 //CONFIG_PM
static void cl1026_pcm_shutdown(struct snd_pcm_substream *substream,struct snd_soc_dai *dai)
{
	CL_DBG(" cl1026_pcm_shutdown\n");
	//struct snd_soc_codec *codec = dai->codec;
	//struct cl4016_priv *cl4016 = snd_soc_codec_get_drvdata(codec);
	return;
}
#else
#define cl1026_pcm_shutdown NULL
#endif
static struct snd_soc_dai_ops cl1026_ops = {
	.startup = cl1026_pcm_startup,
	.hw_params = cl1026_pcm_hw_params,
	.set_fmt = cl1026_set_dai_fmt,
	.set_sysclk = cl1026_set_dai_sysclk,
	.mute_stream = cl1026_mute,
	// .shutdown = cl1026_pcm_shutdown,

};

static struct snd_soc_dai_driver cl1026_dai = {
	.name = "cl1026-asp",
	.playback = {
		.stream_name = "ASP Playback",
		.channels_min = 1,
		.channels_max = 2,
		.rates = CL1026_LRCK,
		.formats = CL1026_FORMATS,
	},
	.capture = {
		.stream_name = "ASP Capture",
		.channels_min = 1,
		.channels_max = 2,
		.rates = CL1026_LRCK,
		.formats = CL1026_FORMATS,
	},
	.ops = &cl1026_ops,
	.symmetric_rates = 1,

};


static int cl1026_i2c_probe(struct i2c_client *i2c_client,
			     const struct i2c_device_id *id)
{
	struct cl1026_priv*cl1026;
	int ret;

	CL_DBG("run driver .... \n");
	cl1026 = devm_kzalloc(&i2c_client->dev, sizeof(struct cl1026_priv),
			       GFP_KERNEL);
	if (!cl1026) {
		CL_ERR("CL1026 " "could not allocate codec\n");
		return -ENOMEM;
	}
    memset(cl1026,0x00,sizeof(struct cl1026_priv));
	cl1026->regmap = devm_regmap_init_i2c(i2c_client, &cl1026_regmap);
	if (IS_ERR(cl1026->regmap)) {
		ret = PTR_ERR(cl1026->regmap);
		CL_ERR("CL1026 ""regmap_init() failed: %d\n", ret);
		return ret;
	}

	i2c_set_clientdata(i2c_client, cl1026);


	globe_cl1026 = cl1026;

	cl1026->hp_mute = 1;
	
	// regcache_cache_bypass(cl1026->regmap, true);
	// CL_DBG(" Cubic Lattice cl1026 0x3F");
	// regcache_cache_bypass(cl1026->regmap, false);

	
	// cl1026->gpiod_spk_ctl = devm_gpiod_get_optional(&i2c_client->dev,"spk-con",GPIOD_OUT_LOW);
	// if (IS_ERR(cl1026->gpiod_spk_ctl)) {
	// 	ret = IS_ERR(cl1026->gpiod_spk_ctl);
	// 	cl1026->gpiod_spk_ctl = NULL;
	// 	dev_warn(&i2c_client->dev, "cannot get spk-con-gpio %d\n", ret);
	// }
	// else{
	// 	gpiod_export(cl1026->gpiod_spk_ctl,0);
	// }

	 ret = devm_snd_soc_register_component(&i2c_client->dev, &soc_codec_dev_cl1026,
	 				      &cl1026_dai, 1);
	

	if (ret < 0) {
		CL_ERR("register codec error %d\n",ret);
		return ret;
	}
	// spk_monitor_wq = alloc_ordered_workqueue("%s",WQ_MEM_RECLAIM | WQ_FREEZABLE, "spk-monitor-wq");
	// INIT_DELAYED_WORK(&spk_delay_work, spk_delay_work_handle);	

	CL_DBG("load end ret=%d\n",ret);

	return 0;
}
static int cl1026_i2c_remove(struct i2c_client *client)
{
	snd_soc_unregister_component(&client->dev);
	return 0;
}
static void cl1026_i2c_shutdown(struct i2c_client *client)
{
	// struct cl1026_priv *cl1026 = i2c_get_clientdata(client);

	if (cl1026_codec != NULL) {
		// cl1026_enable_spk(cl1026, false);
		msleep(20);
		cl1026_set_bias_level(cl1026_codec, SND_SOC_BIAS_OFF);
	}
}


static const struct of_device_id cl1026_of_match[] = {
	{ .compatible = "CubicLattice,cl1026", },
	{ }
};
MODULE_DEVICE_TABLE(of, cl1026_of_match);

static const struct i2c_device_id cl1026_id[] = {
	{"cl1026", 0},
	{}
};
MODULE_DEVICE_TABLE(i2c, cl1026_id);

static struct i2c_driver cl1026_i2c_driver = {
	.driver = {
			.name = "cl1026",
			.of_match_table = cl1026_of_match,
		},
	.probe = cl1026_i2c_probe,
	.remove = cl1026_i2c_remove,
	.shutdown = cl1026_i2c_shutdown,
	.id_table = cl1026_id,
};
module_i2c_driver(cl1026_i2c_driver);

MODULE_DESCRIPTION("ASoC CL1026 driver");
MODULE_AUTHOR("CB Ltd");
MODULE_LICENSE("GPL");
